#pragma once
#include "gtest/gtest.h"

#include "TestData/model/Link_TwentyTruss.hpp"
#include "TestData/model/Link_EvenTwentyTruss.hpp"
#include "TestData/model/Cube_OneHexa8Ele.hpp"
#include "TestData/model/Cube_2x2x2Hexa8Ele.hpp"
#include "../MinimumDegreeSort.h"
#include "../DOFHandler.h"

using SG::FEMSolver::MinimumDegreeSort;
using SG::FEMSolver::DOFHandler;
using SG::Algebra::Graph;

TEST (MinimumDegreeGraphTest, GenerateGraphNodeIdContinueCase)
{
    // Input
    Link_TwentyTruss model;
    auto dbServiceFactory = model.GetModel ();
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes(nodeIds.size());
    for (std::size_t inode = 0 ; inode < nodeIds.size(); ++inode)
    {
         indexes[inode] = inode; 
    }
    // Test data
    MinimumDegreeSort::SortNodeId (nodeIds, indexes);
    auto GenerateGraphgTest = MinimumDegreeSort::GenerateGraph (dbServiceFactory,nodeIds,indexes);
    // Target data
    Graph GenerateGraphgTarget;
    GenerateGraphgTarget.m_pointer = {0,2,5,9,13,15,19,25,30,34,37,40,44,49,55,59,61,65,69,72,74};
    GenerateGraphgTarget.m_neighbour = {1,2,               // node 1's  neighbour
                                        0,2,3,             // node 2's  neighbour
                                        0,1,3,6,           // node 3's  neighbour
                                        1,2,6,7,           // node 4's  neighbour
                                        5,10,              // node 5's  neighbour
                                        4,6,10,11,         // node 6's  neighbour
                                        2,3,5,7,11,12,     // node 7's  neighbour
                                        3,6,8,12,13,       // node 8's  neighbour
                                        7,9,13,14,         // node 9's  neighbour
                                        8,14,15,           // node 10's  neighbour
                                        4,5,11,            // node 11's  neighbour
                                        5,6,10,12,         // node 12's  neighbour
                                        6,7,11,13,16,      // node 13's  neighbour
                                        7,8,12,14,16,17,   // node 14's  neighbour
                                        8,9,13,15,         // node 15's  neighbour
                                        9,14,              // node 16's  neighbour
                                        12,13,17,18,       // node 17's  neighbour
                                        13,16,18,19,       // node 18's  neighbour
                                        16,17,19,          // node 19's  neighbour
                                        17,18};            // node 20's  neighbour
    // Check
    ASSERT_TRUE (GenerateGraphgTest.m_pointer == GenerateGraphgTarget.m_pointer);
    ASSERT_TRUE (GenerateGraphgTest.m_neighbour == GenerateGraphgTarget.m_neighbour);
}

TEST (MinimumDegreeGraphTest, GenerateGraphNodeIdDiscontinuityCase)
{
    // Input
    Link_EvenTwentyTruss model;
    auto dbServiceFactory = model.GetModel ();
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes(nodeIds.size());
    for (std::size_t inode = 0 ; inode < nodeIds.size(); ++inode)
    {
         indexes[inode] = inode; 
    }
    // Test data
    MinimumDegreeSort::SortNodeId (nodeIds, indexes);
    auto GenerateGraphgTest = MinimumDegreeSort::GenerateGraph (dbServiceFactory,nodeIds,indexes);
    // Target data
    Graph GenerateGraphgTarget;
    GenerateGraphgTarget.m_pointer = {0,2,5,9,13,15,19,25,30,34,37,40,44,49,55,59,61,65,69,72,74};
    GenerateGraphgTarget.m_neighbour = {1,2,               // node 1's  neighbour
                                        0,2,3,             // node 2's  neighbour
                                        0,1,3,6,           // node 3's  neighbour
                                        1,2,6,7,           // node 4's  neighbour
                                        5,10,              // node 5's  neighbour
                                        4,6,10,11,         // node 6's  neighbour
                                        2,3,5,7,11,12,     // node 7's  neighbour
                                        3,6,8,12,13,       // node 8's  neighbour
                                        7,9,13,14,         // node 9's  neighbour
                                        8,14,15,           // node 10's  neighbour
                                        4,5,11,            // node 11's  neighbour
                                        5,6,10,12,         // node 12's  neighbour
                                        6,7,11,13,16,      // node 13's  neighbour
                                        7,8,12,14,16,17,   // node 14's  neighbour
                                        8,9,13,15,         // node 15's  neighbour
                                        9,14,              // node 16's  neighbour
                                        12,13,17,18,       // node 17's  neighbour
                                        13,16,18,19,       // node 18's  neighbour
                                        16,17,19,          // node 19's  neighbour
                                        17,18};            // node 20's  neighbour
    // Check
    ASSERT_TRUE (GenerateGraphgTest.m_pointer == GenerateGraphgTarget.m_pointer);
    ASSERT_TRUE (GenerateGraphgTest.m_neighbour == GenerateGraphgTarget.m_neighbour);
}

// 测试 生成图的单元具有超过一条边的情况
TEST (MinimumDegreeGraphTest, GenerateGraphHexaEleTest)
{
    // Input
    Cube_OneHexa8Ele model;
    auto dbServiceFactory = model.GetModel ();
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes(nodeIds.size());
    for (std::size_t inode = 0 ; inode < nodeIds.size(); ++inode)
    {
         indexes[inode] = inode; 
    }
    // Test data
    MinimumDegreeSort::SortNodeId (nodeIds, indexes);
    auto GenerateGraphgTest = MinimumDegreeSort::GenerateGraph (dbServiceFactory,nodeIds,indexes);
    
    // Target data
    Graph GenerateGraphgTarget;
    GenerateGraphgTarget.m_pointer = {0,7,14,21,28,35,42,49,56};
    GenerateGraphgTarget.m_neighbour = {1,2,3,4,5,6,7,          // node 1's  neighbour
                                        0,2,3,4,5,6,7,          // node 2's  neighbour
                                        0,1,3,4,5,6,7,          // node 3's  neighbour
                                        0,1,2,4,5,6,7,          // node 4's  neighbour
                                        0,1,2,3,5,6,7,          // node 5's  neighbour
                                        0,1,2,3,4,6,7,          // node 6's  neighbour
                                        0,1,2,3,4,5,7,          // node 7's  neighbour
                                        0,1,2,3,4,5,6};         // node 8's  neighbour
    // Check
    ASSERT_TRUE (GenerateGraphgTest.m_pointer == GenerateGraphgTarget.m_pointer);
    ASSERT_TRUE (GenerateGraphgTest.m_neighbour == GenerateGraphgTest.m_neighbour);
}

// 模型可以测试具有重复边的情况
TEST (MinimumDegreeGraphTest, GenerateGraphCube_2x2x2Test)
{
    // Input
    Cube_2x2x2Hexa8Ele model;
    auto dbServiceFactory = model.GetModel ();
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes(nodeIds.size());
    for (std::size_t inode = 0 ; inode < nodeIds.size(); ++inode)
    {
         indexes[inode] = inode; 
    }
    // Test data
    MinimumDegreeSort::SortNodeId (nodeIds, indexes);
    auto GenerateGraphgTest = MinimumDegreeSort::GenerateGraph (dbServiceFactory,nodeIds,indexes);
    // Target data
    Graph GenerateGraphgTarget;
    GenerateGraphgTarget.m_pointer = {0,7,18,25,36,53,64,71,82,89,100,117,128,145,171,188,
                                       199,216,227,234,245,252,263,280,291,298,309,316};
    GenerateGraphgTarget.m_neighbour = {1,3,4,9,10,12,13,                                    // node 1's  neighbour
                                        0,2,3,4,5,9,10,11,12,13,14,                          // node 2's  neighbour
                                        1,4,5,10,11,13,14,                                   // node 3's  neighbour
                                        0,1,4,6,7,9,10,12,13,15,16,                          // node 4's  neighbour
                                        0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,           // node 5's  neighbour
                                        1,2,4,7,8,10,11,13,14,16,17,                         // node 6's  neighbour
                                        3,4,7,12,13,15,16,                                   // node 7's  neighbour
                                        3,4,5,6,8,12,13,14,15,16,17,                         // node 8's  neighbour
                                        4,5,7,13,14,16,17,                                   // node 9's  neighbour
                                        0,1,3,4,10,12,13,18,19,21,22,                        // node 10's  neighbour
                                        0,1,2,3,4,5,9,11,12,13,14,18,19,20,21,22,23,         // node 11's  neighbour
                                        1,2,4,5,10,13,14,19,20,22,23,                        // node 12's  neighbour
                                        0,1,3,4,6,7,9,10,13,15,16,18,19,21,22,24,25,         // node 13's  neighbour
                                        0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,22,23,24,25,26,// node 14's  neighbour
                                        1,2,4,5,7,8,10,11,13,16,17,19,20,22,23,25,26,        // node 15's  neighbour
                                        3,4,6,7,12,13,16,21,22,24,25,                        // node 16's  neighbour
                                        3,4,5,6,7,8,12,13,14,15,17,21,22,23,24,25,26,        // node 17's  neighbour
                                        4,5,7,8,13,14,16,22,23,25,26,                        // node 18's  neighbour
                                        9,10,12,13,19,21,22,                                 // node 19's  neighbour
                                        9,10,11,12,13,14,18,20,21,22,23,                     // node 20's  neighbour
                                        10,11,13,14,19,22,23,                                // node 21's  neighbour
                                        9,10,12,13,15,16,18,19,22,24,25,                     // node 22's  neighbour
                                        9,10,11,12,13,14,15,16,17,18,19,20,21,23,24,25,26,   // node 23's  neighbour
                                        10,11,13,14,16,17,19,20,22,25,26,                    // node 24's  neighbour
                                        12,13,15,16,21,22,25,                                // node 25's  neighbour
                                        12,13,14,15,16,17,21,22,23,24,26,                    // node 26's  neighbour
                                        13,14,16,17,22,23,25};                               // node 27's  neighbour
    // Check
    ASSERT_TRUE (GenerateGraphgTest.m_pointer == GenerateGraphgTarget.m_pointer);
    ASSERT_TRUE (GenerateGraphgTest.m_neighbour == GenerateGraphgTarget.m_neighbour);
}  

TEST (MinimumDegreeSortTest, SortCube_2x2x2Test)
{
    // Input
    Cube_2x2x2Hexa8Ele model;
    auto dbServiceFactory = model.GetModel ();
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes(nodeIds.size());
    for (std::size_t inode = 0 ; inode < nodeIds.size(); ++inode)
    {
         indexes[inode] = inode; 
    }
    // Test data
    MinimumDegreeSort::Compute (dbServiceFactory,nodeIds,indexes);
} 

TEST (MinimumDegreeSortTest, TrussEleCase)
{
    // Input
    Link_TwentyTruss model;
    auto dbServiceFactory = model.GetModel ();
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes(nodeIds.size());
    for (std::size_t inode = 0 ; inode < nodeIds.size(); ++inode)
    {
         indexes[inode] = inode; 
    }
    // Test data
    MinimumDegreeSort::Compute (dbServiceFactory, nodeIds, indexes);
}


